import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
  Logger,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

/**
 * 请求参数处理拦截器
 * 基于 NestJS 实现 Java 风格的 ControllerRequestAspect
 * 对应 Java: ControllerRequestAspect
 */
@Injectable()
export class RequestParameterInterceptor implements NestInterceptor {
  private readonly logger = new Logger(RequestParameterInterceptor.name);

  constructor(private reflector: Reflector) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();
    const handler = context.getHandler();
    const className = context.getClass().name;
    const methodName = handler.name;

    // 记录请求开始
    this.logger.debug(`Before: ${className} -> ${methodName}()`);

    // 处理请求参数
    this.processRequestParameters(request);

    return next.handle().pipe(
      tap((data) => {
        // 记录请求结束
        this.logger.debug(
          `${className} -> ${methodName}() ended result => ${JSON.stringify(data)}`,
        );
      }),
    );
  }

  /**
   * 处理请求参数
   * @param request 请求对象
   */
  private processRequestParameters(request: any): void {
    try {
      // 处理查询参数
      this.processQueryParameters(request);

      // 处理请求体参数
      this.processBodyParameters(request);

      // 处理路径参数
      this.processPathParameters(request);
    } catch (error) {
      this.logger.error(
        `Failed to process request parameters: ${error.message}`,
      );
    }
  }

  /**
   * 处理查询参数
   * @param request 请求对象
   */
  private processQueryParameters(request: any): void {
    const query = request.query;
    if (!query || typeof query !== 'object') {
      return;
    }

    // 处理数组参数
    const processedQuery = this.processArrayParameters(query);

    // 下划线转驼峰
    const camelCaseQuery = this.toCamelCase(processedQuery);

    // 更新请求查询参数
    request.query = camelCaseQuery;

    this.logger.debug(
      `Processed query parameters: ${JSON.stringify(camelCaseQuery)}`,
    );
  }

  /**
   * 处理请求体参数
   * @param request 请求对象
   */
  private processBodyParameters(request: any): void {
    const body = request.body;
    if (!body || typeof body !== 'object') {
      return;
    }

    // 处理数组参数
    const processedBody = this.processArrayParameters(body);

    // 下划线转驼峰
    const camelCaseBody = this.toCamelCase(processedBody);

    // 更新请求体参数
    request.body = camelCaseBody;

    this.logger.debug(
      `Processed body parameters: ${JSON.stringify(camelCaseBody)}`,
    );
  }

  /**
   * 处理路径参数
   * @param request 请求对象
   */
  private processPathParameters(request: any): void {
    const params = request.params;
    if (!params || typeof params !== 'object') {
      return;
    }

    // 下划线转驼峰
    const camelCaseParams = this.toCamelCase(params);

    // 更新请求路径参数
    request.params = camelCaseParams;

    this.logger.debug(
      `Processed path parameters: ${JSON.stringify(camelCaseParams)}`,
    );
  }

  /**
   * 处理数组参数
   * @param params 参数对象
   * @returns 处理后的参数对象
   */
  private processArrayParameters(params: any): any {
    if (!params || typeof params !== 'object') {
      return params;
    }

    const processed: any = {};

    for (const key in params) {
      if (params.hasOwnProperty(key)) {
        const value = params[key];

        if (key.endsWith('[]')) {
          // 处理数组参数
          const newKey = key.replace('[]', '');
          if (Array.isArray(value)) {
            processed[newKey] = value;
          } else if (typeof value === 'string') {
            // 逗号分隔的字符串转换为数组
            processed[newKey] = value.split(',').map((item) => item.trim());
          } else {
            processed[newKey] = [value];
          }
        } else {
          processed[key] = value;
        }
      }
    }

    return processed;
  }

  /**
   * 下划线转驼峰
   * @param obj 要转换的对象
   * @returns 转换后的对象
   */
  private toCamelCase(obj: any): any {
    if (obj === null || obj === undefined) {
      return obj;
    }

    if (Array.isArray(obj)) {
      return obj.map((item) => this.toCamelCase(item));
    }

    if (typeof obj === 'object') {
      const result: any = {};
      for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
          const camelKey = this.snakeToCamel(key);
          result[camelKey] = this.toCamelCase(obj[key]);
        }
      }
      return result;
    }

    return obj;
  }

  /**
   * 下划线转驼峰
   * @param str 下划线字符串
   * @returns 驼峰字符串
   */
  private snakeToCamel(str: string): string {
    return str.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase());
  }
}
